#lang racket

(require 2htdp/universe 2htdp/image)

(provide (all-defined-out))

(require "image.rkt")
;............................. Class Animation% ........................................
;Class mère des animations
(define Animation%
  (class object%
    ; Attribut : duree (Durée de l'animation en tick d'horloge), rest (nombre de tick que l'animation devra jouer)
    ;isWorking (si l'animation joue ou pas), img (l'image relier à l'animation), img-ini (l'image initiale pour le reset)
    (init-field (duree 3) (rest 3) )
    (init-field (isFinished #f))
    (define img-ini (new Image%))
    (init-field (img (new Image%)))
    (define isWorking '#f)
    
    ;(define img (make-object Image% img-ini))
    
    ;..................Accesseurs..........................
    
    (define/public (getDuree) duree) ;Renvoi la durée de l'animation
    (define/public (getRest) rest);Renvoi le temps restant de l'animation
    (define/public (isWorking?) isWorking) ;Renvoi si elle joue
    (define/public (getPosX) (send img getPosX)) ;Renvoi la position sur l'axe des abscisses
    (define/public (getPosY) (send img getPosY));Renvoi la position sur l'axe des ordonnées
    (define/public (getImg-ini) img-ini);Renvoie l'image initiale
    (define/public (getImg) img);Renvoie l'image sur laquelle travaille l'animation
    (define/public (getClass) 'Animation%);Renvoie la class
    (define/public (isFinished?) isFinished)
    
    ;.................Mutateurs..................
    
    (define/public (setDuree d) (begin (set! duree d) (set! rest d)));Initialise la durée et donc le temps restant
    (define/public (work) (set! isWorking '#t));L'animation est en fonctionnement
    (define/public (stop) (set! isWorking '#f) (send img set-isAnimated #f));L'animation s'arrète
    (define/public (setRest r) (set! rest r) );Modifie le temps restant
    (define/public (setImg-ini imag) (set! img-ini imag) );Initialise l'image initiale
    ;(define/public (setImg imag) (set! img (make-object (send imag getClass) (send imag getAll)) ))
    (define/public (setImg imag) (set! img imag) );Initialise l'image
    (define/public (set-isFinished bool) (set! isFinished bool))
    
    ;................Méthode jouer()...........
    (define/public (jouer) 
      ;Si l'animation joue et que ce n'est pas son dernier tour
      (cond [(and isWorking (> rest 1))  (set! rest (- rest 1))]
            ;Si l'animation joue et que c'est pas son dernier tour
            [(and isWorking (= rest 1)) (begin (set! isWorking '#f) (set! rest duree))]
            ;Si l'animation ne joue pas
            [(not isWorking) (begin (set! isWorking '#t) (set! rest (- rest 1)))]
            [else (error "wrong")]
            ))
    
    ;................Méthode toString().............
    (define/public (toString)
      (format "<[ ~a | duree ~a | rest ~a | finished ~a ]>"
              (send this getClass)
              (send this getDuree)
              (send this getRest)
              (send this isFinished?)))
    
    (super-new)
  )
)

; ....................................... Class Animation-changer-couleur% ...................................
;Class qui change la couleur d'une image
(define Animation-changer-couleur%
  (class Animation%
    ;(init-field (duree 0) (rest 0) )
    (init-field (couleurs-disponibles (list "red" "green" "blue" "purple" "yellow")))
    
    ;..................Accesseurs..........................
    (define/override (getClass) 'Animation-changer-couleur%);Renvoie la class
    
    ;................Méthode jouer()...........
    (define/override (jouer) 
      ;Si l'animation est en fonctionnement et qu'il lui reste plus d'une tour à jouer on décrémente le compteur de 1
      (cond [(and (send this isWorking?) (> (send this getRest) 1))   (send this setRest (- (send this getRest) 1))]
            ;Si l'animation est en fonctionnement et que c'est son dernier tour de jeu, l'animation est finie.
            [(and (send this isWorking?) (= (send this getRest) 1))   (begin 
                                                                        (send this stop)
                                                                        (send this set-isFinished #t))]
            ;Si l'animation n'est pas en fonctionnement elle démarre, le reste est décrémenté de 1 et l'image prend la
            ;couleur choisi
            [(not (send this isWorking?))   (begin 
                                              (printf "animation not working")
                                              (send this work) 
                                              (send this setRest (- (send this getRest) 1)) 
                                              [send (send this getImg) setCouleur (list-ref couleurs-disponibles (random (length couleurs-disponibles))) ] )]
            ;Sinon il y a une érreur
            [else  (error "Problème de durée")]
            ))
    
    (super-new)
  )
)

; ....................................... Class Animation-lever% ...................................
;Class qui fait osciller une image
(define Animation-lever%
  (class Animation%
    ;(init-field (duree 0) (rest 0) )
    
    ;..................Accesseurs..........................
    (define/override (getClass) 'Animation-lever%)
    
    ;................Méthode jouer()...........
    (define/override (jouer) ; On part sur une lever de 10 sur l'axe des y
      ;Si l'animation est en fonctionnement et qu'il lui reste plus d'une tour à jouer
      (cond [(and (send this isWorking?) (> (send this getRest) 1))   
             ;Si le reste est >= a la durée/2
             (begin (if (>= (send this getRest) (/ (send this getDuree) 2))
                         ;On leve l'image de (10/(la durée / 2))                                                        
                        (send (send this getImg) setPosY [+ (send (send this getImg) getPosY) (/ 10 (/ (send this getDuree) 2) ) ])
                         ;Sinon on baisse l'image de (10/(la durée / 2))                                                        
                        (send (send this getImg) setPosY [- (send (send this getImg) getPosY) (/ 10 (/ (send this getDuree) 2) ) ]) )    
                    ;On décrémente le reste de 1                                                         
                    (send this setRest (- (send this getRest) 1))                                     
                    )]
            ;Si l'animation est en fonctionnement et que c'est son dernier tour de jeu, le reste est réinitialisé à la
            ;durée initiale et l'image reprend sa position d'origine
            [(and (send this isWorking?) (= (send this getRest) 1))   (begin (send this stop) [send (send this getImg) setPosY (send (send this getImg-ini) getPosY)] )]
            ;Si l'animation n'est pas en fonctionnement elle démarre et le reste est décrémenté de 1 et l'image se
            ;lève de (10/(la durée / 2))
            [(not (send this isWorking?))   (begin (send this work) (send this setRest (- (send this getRest) 1)) (send (send this getImg) setPosY [+ (send (send this getImg) getPosY) (/ 10 (/ (send this getDuree) 2) ) ]) )]
            ;Sinon Erreur
            [else  (error "Problème de durée")]
            ))
    
    (super-new)
  )
)

; ....................................... Class Animation-basse% ...................................
;Class qui fonctionne avec une Image% : Balle% et qui fait varier le diamètre de celle-ci
(define Animation-basse%
  (class Animation%
    ;(init-field (duree 0) (rest 0) )
    (define/override (getClass) 'Animation-basse%)
   ; (define/override (jouer) 
     ; (cond [(and (send this isWorking?) (> (send this getRest) 1))   (send this setRest (- (send this getRest) 1))]
           ; [(and (send this isWorking?) (= (send this getRest) 1))   (begin (send this stop) (send this setRest (send this getDuree)) [send (send this getImg) setCouleur (send (send this getImg-ini) getCouleur) ])]
            ;[(not (send this isWorking?))   (begin (send this work) (send this setRest (- (send this getRest) 1)) [send (send this getImg) setCouleur (car coul)] )]
            ;[else  (error "Problème de durée")]
            ;))
    
    (super-new)
  )
)

;(define A (circle 30 'solid "red"))



;...................... TESTS .......................

;" ................. TEST-Animations ................."
;(define B (new Balle% (posX 5) (posY 8) (couleur "blue") (rayon 30)))
;(define D (new Balle% (posX 5) (posY 8) (couleur "blue") (rayon 30)))

;(define C (new Animation-lever% ))

;(send C setDuree 10)








;(define C (new Animation-changer-couleur% ))
;(send C setImg B)
;(send C setImg-ini D)
;"jouer"
;(send C jouer "green")
;(send (send C getImg) getImage)
;(send C getRest)
;(sleep 0.1)
;"jouer 2"
;(send C jouer)
;(send (send C getImg) getImage)
;(send C getRest)
;"jouer 3"
;(sleep 1)
;(send C jouer)
;(send (send C getImg) getImage)
;(send C getRest)
;(sleep 0.1)



